--- title: OpenHSI Class keywords: fastai sidebar: home_sidebar summary: "The bridge between camera implementations and the rest of `openhsi` land." description: "The bridge between camera implementations and the rest of `openhsi` land." nb_path: "nbs/01_capture.ipynb" ---
{% raw %}
{% endraw %} {% raw %}
{% endraw %} {% raw %}
{% endraw %} {% raw %}

class OpenHSI[source]

OpenHSI(n_lines:int=16, processing_lvl:int=-1, preserve_raw:bool=False, json_path:str=None, pkl_path:str=None, print_settings=False) :: DataCube

Base Class for the OpenHSI Camera.
{% endraw %} {% raw %}
{% endraw %} {% raw %}

OpenHSI.collect[source]

OpenHSI.collect()

Collect the hyperspectral datacube.

OpenHSI.avgNimgs[source]

OpenHSI.avgNimgs(n)

Take `n` images and find the average
{% endraw %}

{% include warning.html content='Running in notebook slow downs the camera more than running in a script. ' %}

To add a custom camera, five methods need to be defined in a class to:

  1. Initialise camera __init__, and
  2. Open camera start_cam, and
  3. Close camera stop_cam, and
  4. Capture a picture as a numpy array get_img, and
  5. Update the exposure settings set_exposure, and
  6. [Optional] Poll the camera temperature get_temp.

By inheriting from the OpenHSI class, all the methods to load settings/calibration files, collect datacube, saving data to NetCDF, and viewing as RGB are integrated. Furthermore, the custom camera class can be passed to a SettingsBuilder class for calibration.

For example, we implement a simulated camera below.

{% raw %}

class SimulatedCamera[source]

SimulatedCamera(img_path:str=None, n_lines:int=16, processing_lvl:int=-1, preserve_raw:bool=False, json_path:str=None, pkl_path:str=None, print_settings=False) :: OpenHSI

Simulated camera using an RGB image as an input. Hyperspectral data is produced using CIE XYZ matching functions.
{% endraw %} {% raw %}
{% endraw %} {% raw %}

SimulatedCamera.rgb2xyz_matching_funcs[source]

SimulatedCamera.rgb2xyz_matching_funcs(rgb:ndarray)

convert an RGB value to a pseudo-spectra with the CIE XYZ matching functions.
{% endraw %} {% raw %}
with SimulatedCamera(img_path="assets/great_hall_slide.png", n_lines=1028, processing_lvl = 3, 
                     json_path="assets/cam_settings.json",pkl_path="assets/cam_calibration.pkl") as cam:
    cam.collect()
    fig = cam.show(plot_lib="matplotlib",hist_eq=True)
100%|██████████| 1028/1028 [00:21<00:00, 48.23it/s]
{% endraw %} {% raw %}
fig.opts(fig_inches=7,title="simulated hyperspectral datacube")
{% endraw %}

Each RGB value is converted into a pseudo-spectra by using the CIE XYZ matching functions.

{% raw %}
Text(0, 0.5, 'CIE XYZ value')
{% endraw %}

Loading and processing datacubes further

{% include tip.html content='ProcessRawDatacube only works for raw data captured using processing_lvl = -1. ' %}

{% raw %}

class ProcessRawDatacube[source]

ProcessRawDatacube(fname:str, processing_lvl:int, json_path:str, pkl_path:str, old_style:bool=False) :: OpenHSI

Post-process datacubes
{% endraw %} {% raw %}
{% endraw %} {% raw %}

ProcessRawDatacube.save[source]

ProcessRawDatacube.save(save_dir:str, preconfig_meta_path:str=None, prefix:str='', suffix:str='')

Saves to a NetCDF file (and RGB representation) to directory dir_path in folder given by date with file name given by UTC time.
Override the processing buffer timestamps with the timestamps in original file, also for camera temperatures.
{% endraw %} {% raw %}
json_path = '../calibration_files/OpenHSI-16_settings_Mono8_bin2.json'
pkl_path  = '../calibration_files/OpenHSI-16_calibration_Mono8_bin2_window.pkl'

proc_dc = ProcessRawDatacube(fname = "../../Downloads/16_pvn1_bin2_10ms2022_01_13-04_22_25.nc", processing_lvl=4,
                             json_path=json_path, pkl_path=pkl_path)
proc_dc.collect()
100%|██████████| 1000/1000 [00:07<00:00, 133.57it/s]
{% endraw %} {% raw %}
fig = proc_dc.show(hist_eq=True)
fig
{% endraw %}

If your saved datacubes have already been processed (for example, binned for smaller file size), you can further post-process your datacube using ProcessDatacube. A list of callable transforms can be provided to ProcessDatacube.load_next_tfms, the catch is to remember what transforms have already been applied during data collection and the final desired processing level (binning, radiance output, ...). See the quick start guide for some documentation on what is done for each processing level. {% include warning.html content='next_tfms needs to be valid. For instance, you cannot bin twice!' %}

{% raw %}

class ProcessDatacube[source]

ProcessDatacube(old_style:bool=False) :: ProcessRawDatacube

Post-process datacubes
{% endraw %} {% raw %}
{% endraw %} {% raw %}

ProcessDatacube.load_next_tfms[source]

ProcessDatacube.load_next_tfms(next_tfms:List[Callable[ndarray, ndarray]]=[])

provide the transforms you want to apply to this dataset
{% endraw %} {% raw %}
proced_dc = ProcessDatacube(fname = "../calibration_files/2022_01_13/2022_01_13-04_22_25_proc_lvl_2.nc", processing_lvl=4,
                             json_path=json_path, pkl_path=pkl_path)
proced_dc.load_next_tfms([proc_dc.dn2rad])
proced_dc.collect()
100%|██████████| 1000/1000 [00:01<00:00, 916.42it/s]
{% endraw %} {% raw %}
proced_dc.show(hist_eq=True)
{% endraw %}